package com.huiquan.onlineTime.service;

import com.huiquan.analysis.domain.User;
import com.huiquan.analysis.domain.UserPage;
import com.huiquan.foundation.constant.RoleID;
import com.huiquan.framework.base.BaseService;
import com.huiquan.framework.constant.BaseContants;
import com.huiquan.management.dao.UserAbilityDao;
import com.huiquan.management.dao.UserManageDao;
import com.huiquan.management.domain.UserAbility;
import com.huiquan.management.service.UserManageService;
import com.huiquan.onlineTime.dao.OnlineTimeRecordDao;
import com.huiquan.onlineTime.domain.OnlineTimeRecord;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.concurrent.ConcurrentHashMap;

@Service
public class OnlineTimeRecordService extends BaseService {

	@Autowired
	private OnlineTimeRecordDao onlineTimeRecordDao;
	@Autowired
	private UserManageDao userManageDao;
	@Autowired
	private UserAbilityDao userAbilityDao;

	public static Map<Long, OnlineTimeRecord> recordMap = new ConcurrentHashMap<>();
	private static final long errorSessionMs = 605 * 1000L; // session失效时间为5分钟，该变量为记录中失效时间，两次操作间隔超过该时间表示系统错误

	/**
	 * 用户登录的时候，开始记录在线时间，如果之前存在记录，则先保存之前在线时间记录
	 */
	public void login(User user, Date begin) {
		if (isPayPerTime(user)) {

			Long uid = user.getUserId();
			if (uid == null || begin == null) {
				// 登录的时候参数不能为空
				LOGGER.error("login is error: param is null, uid={}, begin={}", new Object[] { uid, begin });
			} else {
				OnlineTimeRecord record = recordMap.get(uid);
				if (record != null) {
					// 如果map中存在该用户的记录，将该次操作作为维护性操作
					maintain(user, begin);
				} else {
					// 如果map中不存在该用户的记录，则新增一条记录
					addRecord2Map(uid, begin);
				}
			}
		}
	}

	/**
	 * 用户登出的时候，将当前记录保存
	 */
	public void logout(User user, Date end) {
		if (isPayPerTime(user)) {
			Long uid = user.getUserId();
			if (uid == null || end == null) {
				// 登出的时候参数不能为空
				LOGGER.error("logout is error: param is null, uid={}, end={}", new Object[] { uid, end });
			} else {
				// 维护该用户的记录
				OnlineTimeRecord record = recordMap.get(uid);
				update(uid, record, end, 3);
			}
		}
	}

	/**
	 * 用户在登录后的任何操作，维护记录中的结束时间
	 */
	public void maintain(User user, Date end) {
		if (isPayPerTime(user)) {
			Long uid = user.getUserId();
			if (uid == null || end == null) {
				// 操作的时候参数不能为空
				LOGGER.error("maintain is error: param is null, uid={}, end={}", new Object[] { uid, end });
			} else {
				// 维护该用户的记录
				OnlineTimeRecord record = recordMap.get(uid);
				if (record == null) {
					record = addRecord2Map(uid, end);
				}
				update(uid, record, end, 2);
			}
		}
	}

	/**
	 * 重置所有用户的记录
	 */
	public void resetAll(Date end) {
		if (end == null) {
			// 操作的时候参数不能为空
			LOGGER.error("reset is error: param is null, begin={}", new Object[] { end });
		} else {
			// 遍历map中所有用户的记录
			for (Entry<Long, OnlineTimeRecord> tmp : recordMap.entrySet()) {
				OnlineTimeRecord record = tmp.getValue();
				// 判断是否需要更新结束时间
				update(record.getUid(), record, end, 1);
			}
		}
	}

	/**
	 * 
	 * 更新一条记录
	 * 
	 * @param uid
	 * @param record
	 * @param end
	 * @param type
	 *            1-重置；2-维护；3-登出
	 */
	private void update(Long uid, OnlineTimeRecord record, Date end, int type) {
		if (record != null) {
			// 判断当前操作与上一次操作的时间比较，如果超过session过期时间则表示系统有错误
			if ((end.getTime() - record.getEnd().getTime()) > errorSessionMs) {
				// 如果判断当前时间已session过期，则不更新结束时间，保存该记录，然后将该用户在map中重置
				LOGGER.error("update is error: record end time error, uid={}, update={}, record={}, type={}",
						new Object[] { uid, end.getTime(), record.getEnd().getTime(), type });

				saveRecord(record);

				if (type == 2) {
					// 维护的时候需要重新添加记录
					addRecord2Map(uid, end);
				} else {
					// 重置和登出的时候删除该用户的记录
					recordMap.remove(uid);
				}
			} else {
				// 设置记录中的结束时间
				if (type != 1) {
					record.setEnd(end);
				}

				// 正常维护的时候不新增数据
				if (type != 2) {
					saveRecord(record);

					// 重置的时候添加数据后需要重新设置记录
					if (type == 1) {
						record.setBegin(end);
						record.setEnd(end);
					}
				}

				// 如果登出的时候删除该用户的记录
				if (type == 3) {
					recordMap.remove(uid);
				}
			}
		} else {
			// 操作的时候没有记录，系统有错误
			LOGGER.error("update is error: record is null, uid={}, type={}", new Object[] { uid, type });
		}
	}

	/**
	 * 将一条用户在线记录保存
	 */
	private void saveRecord(OnlineTimeRecord record) {
		if (record.getUid() == null || record.getBegin() == null || record.getEnd() == null) {
			LOGGER.error("saveRecord param is error: uid={}, begin={}, end={}",
					new Object[] { record.getUid(), record.getBegin(), record.getEnd() });
			return;
		}

		// 计算开始到结束时间的毫秒数
		Long ms = record.getEnd().getTime() - record.getBegin().getTime();
		if (ms == 0) {
			// 如果结束时间与开始时间一致，则不保存
			return;
		}
		record.setMs(ms.intValue());

		// 保存到数据库
		onlineTimeRecordDao.insert(record);
		LOGGER.info("save record to database; uid=" + record.getUid());
	}

	/**
	 * 在map中添加一条用户数据
	 */
	private OnlineTimeRecord addRecord2Map(Long uid, Date begin) {
		OnlineTimeRecord record = new OnlineTimeRecord();
		record.setUid(uid);
		record.setBegin(begin);
		record.setEnd(begin);

		recordMap.put(uid, record);
		LOGGER.debug("add record to map; uid=" + uid);
		return record;
	}

	/**
	 * 获取默认页面
	 */
	public String getRedirectURL(User user) {
		UserPage userPage = userManageDao.retrievePageByRoleAndTab(user);
		if (userPage != null) {
			return userPage.getUrl();
		} else {
			List<UserPage> userPages = userManageDao.retrieveByRole(user.getRole() + "", UserManageService.PAGE_TAB_TYPE);
			if (userPages != null && userPages.size() > 0) {
				return userPages.get(0).getUrl();
			} else {
				return null;
			}
		}
	}

	public static Map<String, Boolean> incapableFlagMap = new HashMap<>();

	public static void putIncapableFlag(User user, Boolean incapableFlag) {
		incapableFlagMap.put(user.getUserId() + ";" + user.getRole(), false);
	}

	private boolean isPayPerTime(User user) {
		// 管理员不用计时
		boolean isAdmin = RoleID.ADMIN.getId().equals(user.getRole());

		// 测验为通过的用户不计时
		Boolean incapableFlag = incapableFlagMap.get(user.getUserId() + ";" + user.getRole());
		if (incapableFlag == null) {
			incapableFlag = false;

			UserAbility ua = userAbilityDao.retrieveObjectByUserIdAndRuleId(user.getUserId(), user.getRole());
			if (ua != null && !BaseContants.FLAG_YES.equals(ua.getExamPass())) {
				incapableFlag = true;
			}
			incapableFlagMap.put(user.getUserId() + ";" + user.getRole(), incapableFlag);
		}

		if (isAdmin || incapableFlag) {
			return false;
		} else {
			return true;
		}

	}

}
